﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using yq.IBase.DBHelper;
using cn.Util;

namespace yq.IBase.Basis
{
    /// <summary>
    /// 查询对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class SelectBase<T> where T : ModelBase<T>, new()
    {
        internal SelectBase(IList<FuncSQL<T>> _whereList,
            Dictionary<Expression<Func<T, object>>, bool> _ordebyDic,
            string _tableName)
        {
            whereList = _whereList;
            ordebyDic = _ordebyDic;
            tableName = _tableName;
        }

        public SelectBase()
        { 
        
        }

        protected string tableName = null;

        protected T currentT = new T();

        /// <summary>
        /// 多条件集合
        /// </summary>
        internal IList<FuncSQL<T>> whereList = new List<FuncSQL<T>>();

        /// <summary>
        /// 排序集合
        /// </summary>
        protected Dictionary<Expression<Func<T, object>>, bool> ordebyDic = new Dictionary<Expression<Func<T, object>>, bool>();

        /// <summary>
        /// 获取条件和排序方式的SQL语句
        /// </summary>
        /// <returns></returns>
        internal string GetSql(SQLInParameter parameter=null)
        {
            bool bone = true;
            StringBuilder sqlstring = new StringBuilder();
            foreach (var info in whereList)
            {
                if (bone)
                {
                    sqlstring.Append(" where ");
                    bone = false;
                }
                else
                {
                    sqlstring.Append(info.Type== SqlLinkType.And?"AND":"Or");
                }
                sqlstring.Append(" ( " + WhereFunc.Where<T>(info.Fun, parameter) + " )");
            }
            string ordebysql =ordebyDic.Count==0?" ": WhereFunc.OderBy<T>(ordebyDic);

            return sqlstring + ordebysql;
        }

        /// <summary>
        /// 添加排序方式
        /// </summary>
        /// <param name="func"></param>
        /// <returns></returns>
        public SelectBase<T> OderByDesc(Expression<Func<T, object>> func)
        {
            ordebyDic.Add(func,true);
            return this;
        }

        /// <summary>
        /// 添加排序方式
        /// </summary>
        /// <param name="func"></param>
        /// <returns></returns>
        public SelectBase<T> OderBy(Expression<Func<T, object>> func)
        {
            ordebyDic.Add(func,false);
            return this;
        }

        /// <summary>
        /// 添加条件
        /// </summary>
        /// <param name="func"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public SelectBase<T> Where(Expression<Func<T, bool>> func,SqlLinkType type=SqlLinkType.And)
        {
            whereList.Add(new FuncSQL<T> { Fun = func, Type = type });
            return this;
        }


        /// <summary>
        /// 传入sql语句分页查询 
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="page"></param>
        /// <param name="cn"></param>
        /// <returns></returns>
        internal PageList<T> GetPageList(string sql, PageModel page, DbHelper cn)
        {
            int pageCount, count = 0;
            var dt = cn.Paging(sql, page.PageIndex, page.PageSize, out pageCount, out count);
            page.PageCount = pageCount;
            page.Count = count;
            PageList<T> list = currentT.GetPageList(dt);
            list.PagerModel = page;

            return list;
        }

        /// <summary>
        /// 执行多条件查询的单表分页数据(配合多条件集合WherePlus使用)
        /// </summary>
        /// <param name="func"></param>
        /// <param name="page"></param>
        /// <param name="cn"></param>
        /// <returns></returns>
        public virtual PageList<T> ToPageList(PageModel page, DbHelper cn)
        {
            SelectSQL sql = new SelectSQL()
            {
                Table = tableName,
                WhereString = GetSql()
            };
            currentT.GetSelectSql(sql);

            return GetPageList(sql.toSql(), page, cn);
        }

        /// <summary>
        /// 查询单表数据 (配合多条件集合WherePlus使用)
        /// </summary>
        /// <param name="func"></param>
        /// <param name="cn"></param>
        /// <param name="top">返回记录数量</param>
        /// <returns></returns>
        public virtual IList<T> ToList(DbHelper cn,int top=-1)
        {
            var comm = cn.GetSqlStringCommond("");
            SQLInParameter parameter = new SQLInParameter(cn, comm, true);

            SelectSQL sql = new SelectSQL() 
            {
                Table = tableName,
                WhereString = GetSql(parameter) 
            };
            currentT.GetSelectSql(sql);

            if(top!=-1)
            {
                new DbTool().Top(sql, top);
            }

            comm.CommandText = sql.toSql();

            var dt = cn.ExecuteDataTable(comm);

            return currentT.GetIList(dt);
        }

        /// <summary>
        /// 查询单表符合条件的数量
        /// </summary>
        /// <param name="func"></param>
        /// <param name="cn"></param>
        /// <returns></returns>
        public virtual int ToCount(DbHelper cn)
        {
            var comm = cn.GetSqlStringCommond("");
            SQLInParameter parameter = new SQLInParameter(cn, comm, true);

            SelectSQL sql = new SelectSQL()
            {
                Table = tableName,
                WhereString = GetSql(parameter)
            };

            comm.CommandText = currentT.GetSelectCountSql(sql).toSql();

            var val = cn.ExecuteScalar(comm);
            return val == DBNull.Value?0:Convert.ToInt32(val);
        }

        

        /// <summary>
        /// 查询单表单条数据
        /// </summary>
        /// <param name="func"></param>
        /// <param name="cn"></param>
        /// <returns></returns>
        public virtual T ToModel(DbHelper cn, RowLock rowLock = RowLock.Auto)
        {
            var tool = new DbTool();
            var comm = cn.GetSqlStringCommond("");
            SQLInParameter parameter = new SQLInParameter(cn, comm, true);

            SelectSQL sql = new SelectSQL()
            {
                Table = tableName,
                WhereString = GetSql(parameter)
            };
            currentT.GetSelectSql(sql);

            //有锁||在自动的情况下并且开启了事物
            if (rowLock == RowLock.True || (cn.TransType == TransType.Open && rowLock == RowLock.Auto))
            {
                //加锁
                tool.GetRowLock(sql);
            }

            //Top 1 只需要一行
            comm.CommandText = tool.Top(sql,1).toSql();
            var dt = cn.ExecuteDataTable(comm);
            var list = currentT.GetIList(dt);

            return list.Count == 0 ? currentT : list[0];
        }
    }

    /// <summary>
    /// SQL连接方式
    /// </summary>
    public enum SqlLinkType
    {
        /// <summary>
        /// And
        /// </summary>
        And = 0,

        /// <summary>
        /// Or
        /// </summary>
        Or = 1,
    }

    /// <summary>
    /// 是否启用行锁
    /// </summary>
    public enum RowLock
    {
        /// <summary>
        /// 自动
        /// </summary>
        Auto = -1,

        /// <summary>
        /// 不启用
        /// </summary>
        False = 0,

        //启用
        True = 1
    }


    /// <summary>
    /// 包含条件的SQL语句
    /// </summary>
    /// <typeparam name="T"></typeparam>
    internal class FuncSQL<T> where T : ModelBase<T>, new()
    {
        Expression<Func<T, bool>> fun;

        public Expression<Func<T, bool>> Fun
        {
            get { return fun; }
            set { fun = value; }
        }

        SqlLinkType type= SqlLinkType.And;

        public SqlLinkType Type
        {
            get { return type; }
            set { type = value; }
        }
    }


}
